package com.hjh.gameforum.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.hjh.gameforum.dto.*;
import com.hjh.gameforum.entity.User;
import com.hjh.gameforum.enums.UserStatus;
import com.hjh.gameforum.exception.BusinessException;
import com.hjh.gameforum.mapper.UserMapper;
import com.hjh.gameforum.mapper.UserProfileMapper;
import com.hjh.gameforum.result.PageResult;
import com.hjh.gameforum.service.UserProfileService;
import com.hjh.gameforum.service.UserService;
import com.hjh.gameforum.utils.JwtTokenUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.TextStyle;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {

    private final UserMapper userMapper;
    private final PasswordEncoder passwordEncoder;
    private final JwtTokenUtil jwtTokenUtil;
    private final RedisTemplate<String, Object> redisTemplate;
    private final UserProfileMapper userProfileMapper;

    /**
     * 注册参数校验
     */
    private void validateRegisterDto(RegisterDto registerDto) {
        if (!StringUtils.hasText(registerDto.getUsername())) {
            throw new BusinessException("用户名不能为空");
        }

        if (!StringUtils.hasText(registerDto.getEmail())) {
            throw new BusinessException("邮箱不能为空");
        }

        if (!StringUtils.hasText(registerDto.getPassword())) {
            throw new BusinessException("密码不能为空");
        }

        // 简单的密码强度校验
        if (registerDto.getPassword().length() < 8) {
            throw new BusinessException("密码长度至少8位");
        }
    }
    @Override
    @Transactional
    public void register(RegisterDto registerDto) {
        // 参数校验
        validateRegisterDto(registerDto);

        //检查密码和确认密码一致
        if (!registerDto.getPassword().equals(registerDto.getConfirmPassword())) {
            log.warn("注册失败，密码和确认密码不一致: {}", registerDto.getPassword());
            throw new BusinessException("密码和确认密码不一致");
        }
        // 检查用户名是否已存在
        if (userMapper.getUserByName(registerDto.getUsername()) != null ) {
            log.warn("注册失败，用户名已存在: {}", registerDto.getUsername());
            throw new BusinessException("用户名已存在");
        }

        // 检查邮箱是否已注册
        if (userMapper.getUserByEmail(registerDto.getEmail()) != null ) {
            log.warn("注册失败，邮箱已注册: {}", registerDto.getEmail());
            throw new BusinessException("邮箱已被注册");
        }

        // 创建用户实体
        User user = new User();
        user.setUsername(registerDto.getUsername().trim());
        user.setEmail(registerDto.getEmail().trim().toLowerCase());
        user.setLastLogin(LocalDateTime.now());

        // 密码加密
        String encodedPassword = passwordEncoder.encode(registerDto.getPassword());
        user.setPasswordHash(encodedPassword);


        // 保存用户
        try {
            userMapper.save(user);
            userProfileMapper.addUserProfile(user.getUserId());
            log.info("用户注册成功: {}", registerDto.getUsername());
        } catch (Exception e) {
            log.error("用户注册失败: {}", e.getMessage(), e);
            throw new BusinessException("注册失败，请稍后重试");
        }
    }

    @Override
    public LoginToken login(LoginDto loginDto) {
        // 1. 参数处理
        String username = loginDto.getUsername().trim();
        String password = loginDto.getPassword();

        // 2. 查询用户（现在能正确获取passwordHash）
        User user = userMapper.getUserByName(username);
        if (user == null) {
            throw new BusinessException("用户名或密码错误");
        }

        // 3. 验证密码
        if (!passwordEncoder.matches(password, user.getPasswordHash())) {
            throw new BusinessException("用户名或密码错误");
        }

        LocalDateTime now = LocalDateTime.now();
        user.setLastLogin(now);
        userMapper.updateUser(user);

        // 4. 生成Token
        return new LoginToken(
                user.getUserId(),
                jwtTokenUtil.generateToken(user.getUserId(), user.getUsername()),
                user.getRole()
        );

    }

    @Override
    public void updateUser(UserDto userDto) {

        User user = User.builder()
                .userId(userDto.getUserId())
                .username(userDto.getUsername())
                .email(userDto.getEmail())
                .phone(userDto.getPhone())
                .gender(userDto.getGender())
                .avatarUrl(userDto.getAvatarUrl())
                .status(userDto.getStatus())
                .build();

        log.info("更新用户信息：{}", user);
        userMapper.updateUser(user);
    }

    @Override
    public UserDto getCurrentUser() {
        ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attrs == null) {
            throw new BusinessException("无法获取请求信息");
        }
        HttpServletRequest request = attrs.getRequest();
        Object userIdObj = request.getAttribute("userId");
        if (userIdObj == null) {
            throw new BusinessException("未登录");
        }
        Long userId = (Long) userIdObj;
        User user = userMapper.getUserById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        // 转换为UserDto返回
        UserDto userDto = new UserDto();
        userDto.setUserId(user.getUserId());
        userDto.setUsername(user.getUsername());
        userDto.setEmail(user.getEmail());
        userDto.setPhone(user.getPhone());
        userDto.setGender(user.getGender());
        userDto.setAvatarUrl(user.getAvatarUrl());
        userDto.setStatus(user.getStatus());
        userDto.setRole(user.getRole());
        return userDto;
    }

    @Override
    public void setStatus(Long userId, Integer statusId) {
        UserStatus status = UserStatus.active;
        if (statusId==2){
             status = UserStatus.banned;
        }
        if (statusId==3){
             status = UserStatus.suspended;
        }
        userMapper.updateUser(User.builder()
                .userId(userId)
                .status(status)
                .build());
    }

    @Override
    public PageResult<User> getUserList(UserQueryParem userQueryParem) {
        PageHelper.startPage(userQueryParem.getPage(), userQueryParem.getPageSize());
        List<User> userList = userMapper.getUserList();
        Page<User> page = (Page<User>)userList;
        return new PageResult<>(page.getTotal(), page.getResult());
    }

    @Override
    public PageResult<User> searchUser(UserQueryParem userQueryParem) {
        PageHelper.startPage(userQueryParem.getPage(), userQueryParem.getPageSize());
        List<User> userList = userMapper.searchUser(userQueryParem.getUsername());
        Page<User> page = (Page<User>)userList;
        return new PageResult<>(page.getTotal(), page.getResult());
    }

    @Override
    public void setRole(Long userId, Integer role) {
        userMapper.updateUser(User.builder()
                .userId(userId)
                .role(role)
                .build());
    }

    @Override
    public void deleteUser(Long userId) {
        userMapper.deleteUser(userId);
    }

    @Override
    public Map<String, Object> getUserStats(String unit) {
        Map<String, Object> result = new HashMap<>();
        List<String> x = new ArrayList<>();
        List<Integer> y = new ArrayList<>();

        if ("day".equals(unit)) {
            // 最近7天
            for (int i = 6; i >= 0; i--) {
                LocalDate date = LocalDate.now().minusDays(i);
                x.add(date.getDayOfWeek().getDisplayName(TextStyle.SHORT, Locale.CHINA)); // 周几
                int count = userMapper.countByDate(date);
                y.add(count);
            }
        } else if ("week".equals(unit)) {
            // 最近4周
            for (int i = 3; i >= 0; i--) {
                LocalDate monday = LocalDate.now().minusWeeks(i).with(DayOfWeek.MONDAY);
                LocalDate sunday = monday.plusDays(6);
                x.add("第" + (4 - i) + "周");
                int count = userMapper.countByDateRange(monday, sunday);
                y.add(count);
            }
        } else if ("month".equals(unit)) {
            // 最近12个月
            for (int i = 11; i >= 0; i--) {
                YearMonth ym = YearMonth.now().minusMonths(i);
                x.add(ym.getMonthValue() + "月");
                int count = userMapper.countByMonth(ym.getYear(), ym.getMonthValue());
                y.add(count);
            }
        }
        result.put("x", x);
        result.put("y", y);
        return result;
    }

    @Override
    public Map<String, Object> getActiveUserStats() {
        Map<String, Object> result = new HashMap<>();
        List<String> x = new ArrayList<>();
        List<Integer> y = new ArrayList<>();
        for (int i = 6; i >= 0; i--) {
            LocalDate date = LocalDate.now().minusDays(i);
            x.add(date.getDayOfWeek().getDisplayName(TextStyle.SHORT, Locale.CHINA));
            int count = userMapper.ActiveCount(date);
            y.add(count);
        }
        result.put("x", x);
        result.put("y", y);
        return result;
    }

    @Override
    public Long getTotalUsers() {
        return userMapper.getTotalUsers();
    }

    @Override
    public void sendCode(String phone) {
        //校验手机号
        if (!StringUtils.hasText(phone) || !phone.matches("^1[3-9]\\d{9}$")) {
            throw new BusinessException("手机号格式不正确");
        }
        //生成验证码
        String code = RandomUtil.randomNumbers(6);

        //保存验证码到redis
        redisTemplate.opsForValue().set("login-code:"+phone, code, 5, TimeUnit.MINUTES);

        //发送验证码(在控制台打印验证码）
        log.info("发送验证码成功，验证码：{}", code);

    }

    // 手机号验证码登录
    @Override
    public LoginToken login(String phone, String code) {
        // 校验验证码
        String redisCode = (String) redisTemplate.opsForValue().get("login-code:"+phone);
        if (!StringUtils.hasText(redisCode) || !redisCode.equals(code)) {
            throw new BusinessException("验证码错误");
        }
        // 查询用户
        User user = userMapper.getUserByPhone(phone);
        if (user == null) {
            // 用户不存在，创建用户
            user = User.builder()
                    .username("用户" + RandomUtil.randomString(6)) // 随机生成用户名
                    .phone(phone)
                    .passwordHash(passwordEncoder.encode("123456"))
                    .lastLogin(LocalDateTime.now())
                    .role(3)
                    .build();
            userMapper.save(user);
        }
        // 生成token
        return new LoginToken(user.getUserId(), jwtTokenUtil.generateToken(user.getUserId(), user.getUsername()), user.getRole());

    }


}